import FlowMenuContext from '@/components/flow/FlowMenuContext/FlowMenuContext.js';
import {Icon} from 'ant-design-vue';
import Vue from 'vue';
import FlowSupport from '@/components/flow/FlowSupport.js';
import AddNodeCommand from '@/components/flow/cmd/AddNodeCommand.js';
import DeleteNodeCommand from '@/components/flow/cmd/DeleteNodeCommand.js';
import InsertNodeCommand from '@/components/flow/cmd/InsertNodeCommand.js';
import {NewBranchCommand} from '@/components/flow/cmd/NewBranchCommand.js';
import EditGatewayCommand from '@/components/flow/cmd/EditGatewayCommand.js';
import NewBranchForGatewayCommand from '@/components/flow/cmd/NewBranchForGatewayCommand.js';
import EditEdgeCommand from '@/components/flow/cmd/EditEdgeCommand.js';
import NewEmptyBranchCommand from '@/components/flow/cmd/NewEmptyBranchCommand.js';
import NewEmptyBranchForGatewayCommand from '@/components/flow/cmd/NewEmptyBranchForGatewayCommand.js';
import EditorTooltip from '@/components/flow/tooltips/EditorTooltip.js';
import EditStartNodeCommand from '@/components/flow/cmd/EditStartNodeCommand.js';
import EditUserTaskCommand from '@/components/flow/cmd/EditUserTaskCommand.js';
import EditEndNodeCommand from '@/components/flow/cmd/EditEndNodeCommand.js';
import {ShowFlowUserTaskHistory} from "./cmd/ShowFlowUserTaskHistory";

const h = new Vue().$createElement;

export default class SupportInstance {
  model; // 当前模型
  graph;
  container;
  getModel;
  setModel;
  userTaskConfig;
  userConfig;
  taskViewAndAuthConfig;
  processInstanceId;
  globalProperties;
  nodeClickCallback = (...args) => this.onNodeClick(...args);
  viewportchangeCallback = (...args) => this.onViewportChange(...args);

  /**
   * 创建支持实例
   * @param {Object} param0 包含创建实例所需参数的对象
   * @param {Object} param0.graph 图形对象，用于绘制流程图
   * @param {HTMLElement} param0.container 容器元素，流程图将被渲染在其中
   * @param {Function} param0.getModel 获取当前模型的方法
   * @param {Function} param0.setModel 设置当前模型的方法
   * @returns 返回一个支持流程图操作的实例对象
   */
  constructor({graph, container, getModel, setModel, userTaskConfig, taskViewAndAuthConfig, editable, globalProperties,
                service, userConfig, flowPathRecord, history, processInstanceId, fieldComponentRegistry, fieldGroups}) {
    this.graph = graph;
    this.container = container;
    this.getModel = getModel;
    this.setModel = setModel;
    this.userTaskConfig = userTaskConfig;
    this.service = service;
    this.userConfig = userConfig;
    this.flowPathRecord = flowPathRecord;
    this.fieldComponentRegistry = fieldComponentRegistry;
    this.history = history
    this.editable = editable;
    this.fieldGroups = fieldGroups
    this.processInstanceId = processInstanceId
    this.taskViewAndAuthConfig = taskViewAndAuthConfig
    this.globalProperties = globalProperties
    this.bindResize(container); // 绑定窗口大小改变事件
    // EditorTooltip.bind(this);
  }

  /**
   * 绑定元素大小变化的监听器，当容器大小变化时，重新渲染流模型。
   * @param {Element} container - 被监听大小变化的容器元素。
   */
  bindResize(container) {
    let timer = undefined; // 定时器变量，用于延迟执行重新渲染

    // 使用ResizeObserver监听容器的大小变化
    let observe = new ResizeObserver(([{target}]) => {
      // 如果定时器已设置，则清除并重置定时器
      if (timer) {
        clearTimeout(timer);
        timer = undefined;
      }
      // 设置定时器，延迟执行重新渲染流模型的操作
      timer = setTimeout(() => {
        this.reRenderFlowModel(); // 调用实例方法重新渲染流模型
        clearTimeout(timer); // 清除定时器
        timer = undefined; // 重置定时器变量
      }, 200);
    });

    // 开始观察容器的大小变化
    observe.observe(container);
  }

  /**
   * 重新渲染流程模型
   * @param {Object} model 要渲染的模型，如果未提供，则使用当前模型
   */
  reRenderFlowModel(model) {
    if (!model) {
      model = JSON.parse(JSON.stringify(this.model)); // 复制当前模型
    }
    this.model = model;
    if (!model) return;

    this.graph.changeSize(this.container.offsetWidth, this.container.offsetHeight); // 更新图形大小以适应容器
    this.graph.data(FlowSupport.resolveGraphProperties(model, this)); // 设置图形数据
    const zoom = this.graph.getZoom();
    this.graph.render(); // 渲染图形
    this.graph.zoomTo(zoom);
    this.bindClick(this.graph); // 绑定点击事件
    this.graph.off(this.viewportchangeCallback);
    this.graph.on('viewportchange', this.viewportchangeCallback);
    if (this.position) {
      this.graph.translate(...this.position);
    }
    this.bindToolTip()
  }

  bindToolTip() {
    this.editorTooltip = (this.editorTooltip && this.editorTooltip.unbind() || new EditorTooltip(this)).bind()
  }

  onViewportChange(e) {
    if (e.action === 'translate') {
      let matrix = e.matrix;
      this.position = [matrix[6], matrix[7]];
    }
  }

  /**
   * 绑定图形元素的点击事件
   * @param {Object} graph 图形对象
   * @param {Object} instance 当前实例对象
   */
  bindClick(graph) {
    // 预览去除点击事件
    if (this.history || !this.editable) {
      this.click = this.notClick
    }
    let doBind = () => {
      let eles = document.querySelectorAll('.h-flow-node'); // 获取所有节点元素
      (eles || []).forEach(el => {
        el.removeEventListener("click", this.nodeClickCallback); // 移除旧的点击事件监听器
        el.addEventListener("click", this.nodeClickCallback); // 添加新的点击事件监听器
      });
    };

    graph.on('afterrender', doBind); // 绘制后绑定点击事件
    graph.on('mouseup', doBind); // 鼠标抬起时绑定点击事件
    graph.on('wheel', doBind); // 滚轮事件时绑定点击事件
  }

  /**
   * 点击事件处理函数
   * @param {Object} event 事件对象，包含目标元素和鼠标位置信息
   */
  onNodeClick({target, clientX: x, clientY: y}) {
    let role = this.getRole(target); // 获取元素角色
    let nodeId = this.getNodeId(target); // 获取节点ID
    this.click[role](nodeId, {x, y}); // 调用对应的角色处理函数
  }

  getNodeId(el) {
    let res = el.getAttribute("data-id");
    if (!res) {
      let className = [...el.classList].find(c => c && c.startsWith('data-id-'));
      if (className) {
        res = className.substring('data-id-'.length);
      }
    }
    return res;
  }

  getRole(el) {
    let res = el.getAttribute("data-role");
    if (!res) {
      let className = [...el.classList].find(c => c && c.startsWith('data-role-'));
      if (className) {
        res = className.substring('data-role-'.length);
      }
    }
    return res;
  }

  notClick = {
    edge: () => {

    },
    gateway: () => {

    },
    startNode: () => {

    },
    endNode: () => {

    },
    empty: () => {

    },
    userTask: (nodeId, point) => {
      new ShowFlowUserTaskHistory(this, nodeId).serve();
    }
  }


  click = {
    edge: (nodeId, point) => {
      new EditEdgeCommand(this, nodeId, this.fieldComponentRegistry).serve();
    },
    gateway: (nodeId, point) => {
      if ((this.getModel().gatewayPairs || []).find(g => g.source === nodeId)) {
        let context = FlowMenuContext.showMenuContext([
          // 显示菜单选项
          {
            title: '插入任务', icon: h(Icon, {props: {type: 'pull-request'}}),
            click: () => context && context.close && (context.close() || new InsertNodeCommand(this, nodeId).serve()),
          },
          {
            title: '增加分支', icon: h(Icon, {props: {type: 'share-alt'}}),
            click: () => context && context.close && (context.close() || new NewBranchForGatewayCommand(this, nodeId).serve()),
          },
          {
            title: '增加空分支', icon: h(Icon, {props: {type: 'share-alt'}}),
            click: () => context && context.close && (context.close() || new NewEmptyBranchForGatewayCommand(this, nodeId).serve()),
          },
          {
            title: '属性', icon: h(Icon, {props: {type: 'edit'}}),
            click: () => context.close && (context.close() || new EditGatewayCommand(this, nodeId).serve())
          }
        ], point);
      } else {
        let context = FlowMenuContext.showMenuContext([
          // 显示菜单选项
          {
            title: '添加任务', icon: h(Icon, {props: {type: 'plus'}}),
            click: () => context && context.close && (context.close() || new AddNodeCommand(this, nodeId).serve()),
          },
          {
            title: '增加分支', icon: h(Icon, {props: {type: 'share-alt'}}),
            click: () => context && context.close && (context.close() || new NewBranchForGatewayCommand(this, nodeId).serve()),
          },
          {
            title: '增加空分支', icon: h(Icon, {props: {type: 'share-alt'}}),
            click: () => context && context.close && (context.close() || new NewEmptyBranchForGatewayCommand(this, nodeId).serve()),
          }
        ], point);
      }
    },
    startNode: (nodeId, point) => {
      let context = FlowMenuContext.showMenuContext([
        // 显示菜单选项
        {
          title: '添加任务', icon: h(Icon, {props: {type: 'plus'}}),
          click: () => context && context.close && (context.close() || new AddNodeCommand(this, 'start').serve()),
        },
        {
          title: '属性', icon: h(Icon, {props: {type: 'edit'}}),
          click: () => context && context.close && (context.close() || new EditStartNodeCommand(this, 'start').serve()),
        }
      ], point);
    },
    endNode: (nodeId, point) => {
      let context = FlowMenuContext.showMenuContext([
        // 显示菜单选项
        {
          title: '插入任务', icon: h(Icon, {props: {type: 'pull-request'}}),
          click: () => context && context.close && (context.close() || new InsertNodeCommand(this, 'end').serve()),
        },
        {
          title: '属性', icon: h(Icon, {props: {type: 'edit'}}),
          click: () => context && context.close && (context.close() || new EditEndNodeCommand(this, 'end').serve()),
        }
      ], point);
    },
    empty: (nodeId, point) => {
      let context = FlowMenuContext.showMenuContext([
        // 显示菜单选项
        {
          title: '删除空节点', icon: h(Icon, {props: {type: 'delete'}}), danger: true,
          click: () => context && context.close && (context.close() || new DeleteNodeCommand(this, nodeId).serve())
        },
        {
          title: '增加分支', icon: h(Icon, {props: {type: 'share-alt'}}),
          click: () => context && context.close && (context.close() || new NewBranchCommand(this, nodeId).serve()),
        }
      ], point);
    },
    userTask: (nodeId, point) => {
      let context = FlowMenuContext.showMenuContext([
        // 显示菜单选项
        {
          title: '添加任务', icon: h(Icon, {props: {type: 'plus'}}),
          click: () => context && context.close && (context.close() || new AddNodeCommand(this, nodeId).serve()),
        },
        {
          title: '插入任务', icon: h(Icon, {props: {type: 'pull-request'}}),
          click: () => context && context.close && (context.close() || new InsertNodeCommand(this, nodeId).serve()),
        },
        {
          title: '增加分支', icon: h(Icon, {props: {type: 'share-alt'}}),
          click: () => context && context.close && (context.close() || new NewBranchCommand(this, nodeId).serve()),
        },
        {
          title: '增加空分支', icon: h(Icon, {props: {type: 'share-alt'}}),
          click: () => context && context.close && (context.close() || new NewEmptyBranchCommand(this, nodeId).serve()),
        },
        {
          title: '删除任务', icon: h(Icon, {props: {type: 'delete'}}), danger: true,
          click: () => context && context.close && (context.close() || new DeleteNodeCommand(this, nodeId).serve())
        },
        {
          title: '属性', icon: h(Icon, {props: {type: 'edit'}}),
          click: () => context && context.close && (context.close() || new EditUserTaskCommand(this, nodeId).serve())
        }
      ], point);
    }
  };
}
